#pragma once 

#include<iostream>
#include<cerrno>
#include<cstring>
#include<cstdlib>
#include<functional>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<unordered_map>
#include"err.hpp"
#include"Thread.hpp"
#include"lockGuard.hpp"
#include"RingQueue.hpp"


namespace ns_server
{
    const static uint16_t default_port=8080; //默认端口号   
    using func_t = std::function<std::string(std::string)>;

    class UdpServer
    {
    public:
        UdpServer(uint16_t port=default_port):port_(port)
        {
            std::cout<<"Server addr:"<<port_<<std::endl;
            pthread_mutex_init(&lock,nullptr);
            p=new Thread(1,std::bind(&UdpServer::Recv,this));
            c=new Thread(1,std::bind(&UdpServer::Broadcast,this));
        }

        void start()
        {
            //1、创建网络套接字接口（socket）,打开网络文件
            sock_=socket(AF_INET,SOCK_DGRAM,0);
            if(sock_<0)
            {
                std::cerr<<"create socket error:"<<strerror(errno)<<std::endl;
                exit(SOCKET_ERR);
            }
            std::cout << "create socket success: " << sock_ << std::endl; //3
            
            //2、给服务器指明ip地址和端口号
            struct sockaddr_in local; //这个local在用户空间的特定函数的栈帧上，不在内核中
            bzero(&local,sizeof(local));

            local.sin_family = AF_INET; // PF_INET
            local.sin_port=htons(port_);
            //inet_addr:1,2
            //1、子谷川风格的IP地址，转换成四字节int，"1.1.1.1"->uint32_t->不能强制转换，需要自己转换（序列化）
            //2、需要将主机序列转换成网络序列
            //3、云服务器，或者一款服务器，一半不要指明某一个确定的IP
            local.sin_addr.s_addr=INADDR_ANY;

            if(bind(sock_,(struct sockaddr*)&local,sizeof(local))<0)
            {
                std::cerr<<"bind scoket error:"<<strerror(errno)<<std::endl;
                exit(BIND_ERR);
            }
            std::cout<<"bind socket success:"<<sock_<<std::endl;
            p->run();
            c->run();
        }


        void addUser(const std::string &name,const struct sockaddr_in &peer)
        {
            //onlineuserp[name]=peer;
            LockGuard lockguard(&lock);
            auto iter=onlineuser.find(name);
            if(iter!=onlineuser.end()) return;

            onlineuser.insert(std::pair<const std::string,const struct sockaddr_in>(name,peer));
        }


        void Recv()
        {
            char buffer[1024];
            while(true)
            {
                //收
                struct sockaddr_in peer;
                socklen_t len=sizeof(peer);   //未来传入缓冲区的大小
                int n=recvfrom(sock_,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
                if(n>0)
                {
                    buffer[n]='\0';
                }
                else
                {
                    continue;
                }
                std::cout<<"recv done..."<<std::endl;

                //提取client信息 --debug
                std::string clientip=inet_ntoa(peer.sin_addr);
                uint16_t clientport=ntohs(peer.sin_port);
                std::cout<<clientip<<"-"<<clientport<<"#"<<buffer<<std::endl;

                //构建一个用户，并检查
                std::string name=clientip;
                name+="-";
                name+=std::to_string(clientport);
                //如果用户不存在，就插入，如果存在，什么都不做
                addUser(name,peer);
                rq.push(buffer);

                //做业务处理
                //std::string message=server_(buffer);
                
                //发
                //sendto(sock_,message.c_str(),message.size(),0,(struct sockaddr*)&peer,sizeof(peer));
            }
        }

        void Broadcast()
        {
            while(true)
            {
                std::string sendstring;
                rq.pop(&sendstring);
                std::vector<struct sockaddr_in> v;

                {
                    LockGuard lockguard(&lock);
                    for(auto user:onlineuser)
                    {
                        v.push_back(user.second);
                    }
                }
                
                for(auto user:v)
                {
                    sendto(sock_,sendstring.c_str(),sendstring.size(),0,(struct sockaddr*)&(user),sizeof(user));
                    std::cout<<"send done..."<<sendstring<<std::endl;
                }
            }
        }

        ~UdpServer()
        {
            pthread_mutex_destroy(&lock);
            c->join();
            p->join();

            delete c;
            delete p;
        }


    private:
        int sock_;
        uint16_t port_;
        //func_t service_; //我们的网络服务器刚刚解决的是网络IO的问题，要惊醒业务处理
        std::unordered_map<std::string,struct sockaddr_in> onlineuser;
        pthread_mutex_t lock;
        RingQueue<std::string> rq;
        Thread*c;
        Thread*p;

        std::string ip_; //到后面就不用这个ip
    };
}